//
//  AirDataStreamBuffer.h
//  AirCpp
//
//  Created by Penghao on 14-4-14.
//  Copyright (c) 2014年 PengHao. All rights reserved.
//

#ifndef AirCpp_AirDataStreamBuffer_h
#define AirCpp_AirDataStreamBuffer_h

#include <iostream>
#include "../AirObject/AirObject.h"
namespace AirCpp{
    class AirDataStreamBuffer : public AirObject{
        typedef enum{
            IN_STREAM = 1,
            OUT_STREAM = 2,
        } STREAM_TYPE;
    private:
        bool is_body_allocated;
        STREAM_TYPE strema_type;
    protected:
        AirBit8 *c_data;
        AirSize_t length_size;
        AirSize_t filled_length;
        AirSize_t *p_length;
        void allocate_head(){
            c_data = (AirBit8 *)malloc(length_size);
            memset(c_data, 0, length_size);
            p_current = c_data;
            p_length = (AirSize_t *)c_data;
        }
        
        void allocate_body(){
            is_body_allocated = true;
            AirBit8 *tmp = (AirBit8 *)malloc(*p_length);
            memset(tmp, 0, *p_length);
            memcpy(tmp, c_data, filled_length);
            p_current = tmp+length_size;
            free(c_data);
            c_data = tmp;
            p_length = (AirSize_t *)c_data;
        }
        
        AirDataStreamBuffer():c_data(NULL), p_current(NULL), length_size(sizeof(AirSize_t)), filled_length(0), is_body_allocated(false){
        }
        
    public:
        AirBit8 *p_current;
        static AirDataStreamBuffer* creat_instream_http_buffer(AirSize_t length){
            AirDataStreamBuffer *buffer = new AirDataStreamBuffer();
            buffer->strema_type = IN_STREAM;
            buffer->c_data = (AirBit8 *)malloc(length);
            memset(buffer->c_data, 0, length);
            buffer->p_current = buffer->c_data;
            return buffer;
        }
        
        static AirDataStreamBuffer* create_instream_buffer(AirSize_t length){
            AirDataStreamBuffer *buffer = new AirDataStreamBuffer();
            buffer->strema_type = IN_STREAM;
            buffer->c_data = (AirBit8 *)malloc(length);
            memset(buffer->c_data, 0, length);
            memcpy(buffer->c_data, &length, buffer->length_size);
            buffer->p_current = buffer->c_data+buffer->length_size;
            buffer->p_length = (AirSize_t *)buffer->c_data;
            return buffer;
        };
        
        static AirDataStreamBuffer* create_outstream_buffer(){
            AirDataStreamBuffer *buffer = new AirDataStreamBuffer();
            buffer->strema_type = OUT_STREAM;
            buffer->allocate_head();
            return buffer;
        }
        
        template <typename T>
        void append_data(const T &data){
            append_c_data((AirBit8 *)&data, sizeof(T));
        }
        
        
        void reset_p_current(){
            p_current = c_data;
        }
        void append_c_data(AirBit8 *data, AirSize_t length_){
            if (strema_type == IN_STREAM) {
                memcpy(p_current, data, length_);
                p_current+=length_;
                filled_length+=length_;
            }else{
                
            }
        }
        
        template <typename T>
        void read_data(T &data){
            read_c_data((AirBit8 *)&data, sizeof(T));
        }
        
        void read_c_data(AirBit8 *data, AirSize_t length_){
            memcpy(data, p_current, length_);
            p_current+=length_;
        }
        
        AirBit8 *get_c_data(){
            return c_data;
        }
        
        AirSize_t length(){
            return *p_length;
        }
        
        
        void clear(){
            filled_length = 0;
            is_body_allocated = false;
            free(c_data);
            allocate_head();
        }
        
        bool is_get_data_length(){
            return filled_length >= length_size;
        }
        
        bool is_get_full_data(){
            return (is_body_allocated && filled_length == *p_length);
        }
        
        AirSize_t get_unrecived_size(){
            return *p_length - filled_length + length_size;
        }
        
        void filled_size(AirSize_t size){
            filled_length += size;
            if (!is_body_allocated&&is_get_data_length()) {
                allocate_body();
            }else{
                p_current+=size;
            }
        }
        
        void desc(){
            printf("filled_length = %d, length = %d\n", filled_length, *p_length);
            for (int i = 0; i < filled_length; ++i) {
                printf("%2x", *(c_data+i));
            }
            printf("\n");
        }
        
        ~AirDataStreamBuffer(){
            printf("dealloc %p\n",this);
            if (c_data!=NULL) {
                free(c_data);
            }
        }
        
    };
}

#endif
